package com.hz.monitoring.module.hardware.socket.ifwl_gprs_v2.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.hz.monitoring.module.hardware.controller.admin.mcu_tenant_resource.vo.McuTenantResourceListReqVO;
import com.hz.monitoring.module.hardware.controller.admin.monitoring_data.vo.MonitoringDataCreateReqVO;
import com.hz.monitoring.module.hardware.controller.admin.monitoring_warning_log.vo.MonitoringWarningLogCreateReqVO;
import com.hz.monitoring.module.hardware.controller.admin.sensor_tenant_resource.vo.SensorTenantResourceListReqVO;
import com.hz.monitoring.module.hardware.controller.admin.sensor_tenant_resource.vo.SensorTenantResourceRespVO;
import com.hz.monitoring.module.hardware.controller.admin.vo.CustomSensorAttribute;
import com.hz.monitoring.module.hardware.controller.admin.vo.CustomValueFields;
import com.hz.monitoring.module.hardware.controller.admin.vo.CustomWarningAttribute;
import com.hz.monitoring.module.hardware.convert.sensor_tenant_resource.SensorTenantResourceConvert;
import com.hz.monitoring.module.hardware.dal.dataobject.mcu_tenant_resource.McuTenantResourceDO;
import com.hz.monitoring.module.hardware.dal.dataobject.sensor_tenant_resource.SensorTenantResourceDO;
import com.hz.monitoring.module.hardware.service.mcu_tenant_resource.McuTenantResourceService;
import com.hz.monitoring.module.hardware.service.monitoring_data.MonitoringDataService;
import com.hz.monitoring.module.hardware.service.monitoring_warning_log.MonitoringWarningLogService;
import com.hz.monitoring.module.hardware.service.sensor_tenant_resource.SensorTenantResourceService;
import com.hz.monitoring.module.hardware.service.warning_contact.WarningContactService;
import com.hz.monitoring.module.hardware.socket.util.BinHexOctUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static com.hz.monitoring.module.hardware.socket.ifwl_gprs_v2.util.InstructionCode.*;

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * 日志
     */
    private Logger log = LoggerFactory.getLogger(getClass());


    private final McuTenantResourceService mcuTenantResourceService;


    private final SensorTenantResourceService sensorTenantResourceService;


    private final MonitoringDataService monitoringDataService;

    private final WarningContactService warningContactService;

    private final MonitoringWarningLogService monitoringWarningLogService;


    /**
     * 管理一个全局map，保存连接进服务端的通道数量
     */
    private static final ConcurrentHashMap<ChannelId, McuTenantResourceDO> CHANNEL_MCU = new ConcurrentHashMap<>();

    private static final ConcurrentHashMap<ChannelId, List<SensorTenantResourceRespVO>> CHANNEL_SENSOR = new ConcurrentHashMap<>();
    ExecutorService executor = Executors.newFixedThreadPool(5);

    public NettyServerHandler(McuTenantResourceService mcuTenantResourceService, SensorTenantResourceService sensorTenantResourceService, MonitoringDataService monitoringDataService, WarningContactService warningContactService, MonitoringWarningLogService monitoringWarningLogService) {
        this.mcuTenantResourceService = mcuTenantResourceService;
        this.sensorTenantResourceService = sensorTenantResourceService;
        this.monitoringDataService = monitoringDataService;
        this.warningContactService = warningContactService;
        this.monitoringWarningLogService = monitoringWarningLogService;
    }

    /**
     * 对每一个传入的消息都要调用；
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            String message = msg.toString();
            log.info("message内容:" + message);
         /*
            1)首次注册的注册包
            2)包含应用数据的数据包
            3)维持链路的心跳包
            */
            //TODO 进行消息长度判断
            if (message.length() == 2) {//维持链路的心跳包
                log.info("心跳包:" + message);
            } else if (message.indexOf(INSTRUCTION_BEGINNING) == 0) { //包含应用数据的数据包
                dataPackage(message, ctx);
            } else if (message.length() == 42) {//首次注册的注册包
                registrationPacket(message, ctx);
                //nodeWakes(message,ctx);
            }else{
                System.out.println("不能解析的数据："+message);
            }
            //ctx.writeAndFlush(FE);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("channelRead解析数据时异常:" + e.getMessage(), e);
        }
    }

    private void dataPackage(String message, ChannelHandlerContext ctx) throws Exception {
        if (!validationData(message)) {
            log.error("数据校检出错，不进行数据处理");
            return;
        }

        System.out.println("应用数据包："+message);

        String instruction = message.substring(12, 16);
        switch (instruction) {
            case NODE_WAKES://:节点唤醒，发送节点自身信息
                nodeWakes(message, ctx);
                break;
            //case PLATFORM_DELIVERS_SYNCHRONIZATION_TIME://平台下发同步时间指令
            //    ???
            case NODE_SYNCHRONIZATION_TIME_REPLY: //节点对时间同步指令的应答
                nodeSynchronizationTimeReply(message, ctx);
                break;
            //   case PLATFORM_DELIVERS_COLLECT_INSTRUCTION: //平台下发采集指令
            //       ???
            case NODE_RECEIVE_COLLECT_INSTRUCTION: //节点接收到一条采集指令
                log.info("节点回应收到一条采集指令！");
                break;
            case NODE_RECEIVE_ALL_COLLECT_INSTRUCTION: //节点接收到全部采集指令
                log.info("节点回应收到全部采集指令！");
                break;
            case PLATFORM_RECEIVE_COLLECT_DATA: //节点上传采集数据
                platformReceiveCollectData(message, ctx);
                break;
            // case PLATFORM_RECEIVE_COLLECT_DATA_REPLY: //平台收到节点的上传数据后进行应答
            //    ???
            case NODE_DORMANCY: //节点进入休眠
                log.info("节点进入休眠！");
                break;
            default:
                log.error("无法解析的指令：" + instruction);
                break;
        }
    }

    /**
     * 节点唤醒，发送节点自身信息，到平台
     */
    private void nodeWakes(String message, ChannelHandlerContext ctx) {
        //  数据解析 目前不处理
         //id
         String id = message.substring(16, 20);
         log.info("id："+BinHexOctUtil.hexStringToString(id));
         //数据区长度
         String dataLengthHex = message.substring(20, 24);
         log.info("数据区长度："+Integer.parseInt(dataLengthHex, 16));
         // 01  供电方式
         String powerSupplyMode = message.substring(24, 26);
         log.info("供电方式:"+BinHexOctUtil.hexStringToString(powerSupplyMode));
         //5A 电量  转换（成10进制后，为90 ，代表90%电量）
         String electricity = message.substring(26, 28);
         log.info("电量:"+BinHexOctUtil.hexStringToString(electricity));
         //00 通道配置版本号，如果没配置信息为FF。 其他情况为 00
         String version = message.substring(28, 30);
         log.info("通道配置版本号:"+BinHexOctUtil.hexStringToString(version));
         // 00 为数据积压个数
         String numberBacklog = message.substring(28, 30);
         log.info("为数据积压个数:"+BinHexOctUtil.hexStringToString(numberBacklog));
         //  00 3C DTU等待上线时间  （00 3C 转换成10进制为60 ，代表60秒）
         String waitingTime = message.substring(message.length() - 10, message.length() - 6);
         log.info("DTU等待上线时间:"+Integer.parseInt(waitingTime, 16));
        //返回结果
        StringBuffer resultHead = new StringBuffer();
        resultHead.append(INSTRUCTION_BEGINNING);
        resultHead.append(PLATFORM_DELIVERS_SYNCHRONIZATION_TIME);
        resultHead.append(MID);
        StringBuffer resultInterval = new StringBuffer();
        Date date = new Date();
        String dataYear = BinHexOctUtil.intToHexString(DateUtil.year(date), 4);
        String dataMonth = BinHexOctUtil.intToHexString(DateUtil.month(date) + 1, 2);
        String dataDayOfMonth = BinHexOctUtil.intToHexString(DateUtil.dayOfMonth(date), 2);
        String dataHour = BinHexOctUtil.intToHexString(DateUtil.hour(date, true), 2);
        String dataMinute = BinHexOctUtil.intToHexString(DateUtil.minute(date), 2);
        String dataSecond = BinHexOctUtil.intToHexString(DateUtil.second(date), 4);
        McuTenantResourceDO mcuTenantResourceDO = CHANNEL_MCU.get(ctx.channel().id());
        if (mcuTenantResourceDO == null) {
            log.error("没有对应的设备，不进行数据处理！");
            return;
        }
        String cycle = BinHexOctUtil.intToHexString(mcuTenantResourceDO.getCycle(), 4);
        resultInterval.append(dataYear);
        resultInterval.append(dataMonth);
        resultInterval.append(dataDayOfMonth);
        resultInterval.append(dataHour);
        resultInterval.append(dataMinute);
        resultInterval.append(dataSecond);
        resultInterval.append(cycle);
        resultInterval.append(WAITING_TIME);
        resultInterval.append(WAITING_REPLY_TIME);
        resultInterval.append(NEW_CONFIGURATION1);//发送新的配置
        resultInterval.append(DATA_FILLING5);
        //进行数据回写
        channelWrite(resultHead, resultInterval.toString(), ctx);

    }

    /**
     * 节点对时间同步指令的应答
     *
     * @param message
     * @param ctx
     */
    private void nodeSynchronizationTimeReply(String message, ChannelHandlerContext ctx) {
        /**  数据解析 目前不处理
         //id
         String id = message.substring(16, 20);
         log.info(BinHexOctUtil.hexStringToString(id));
         //数据区长度
         String dataLengthHex = message.substring(20, 24);
         log.info(""+Integer.parseInt(dataLengthHex, 16));


         // 0B 1C 07 下发时间 11:28:07
         // 0B 1C 07  节点当前时间 11:28:07
         // AC 4C   CRC16 校验码，从帧头开始，到数据区结尾。
         // EF  指令固定结尾

         //下发时间 H时
         String issuedTimeH = message.substring(24, 26);
         //下发时间 m分
         String issuedTimeH = message.substring(26, 28);
         //下发时间 s秒
         String issuedTimeH = message.substring(28, 30);

         //节点当前时间 H时
         String nodeTimeH = message.substring(30, 32);
         //节点当前时间 m分
         String nodeTimeH = message.substring(32, 34);
         //节点当前时间 s秒
         String nodeTimeH = message.substring(34, 36);
         */

        //返回结果
        StringBuffer resultHead = new StringBuffer();
        resultHead.append(INSTRUCTION_BEGINNING);
        resultHead.append(PLATFORM_DELIVERS_COLLECT_INSTRUCTION);
        resultHead.append(MID);
        //数据区
        StringBuffer resultInterval = new StringBuffer();
        //是否数据尾包
        resultInterval.append(WHETHER_DATA_TAIL_PACKET1);


        List<SensorTenantResourceRespVO> sensorList = CHANNEL_SENSOR.get(ctx.channel().id());
        if (CollectionUtil.isEmpty(sensorList)) {
            sensorList = new ArrayList<>();
        }

        String instructionQuantity = BinHexOctUtil.intToHexString(sensorList.size(), 2);
        //总通道指令个数
        resultInterval.append(instructionQuantity);
        //该分包通道指令个数 2个
        resultInterval.append(instructionQuantity);

        //处理振弦传感器
        List<SensorTenantResourceRespVO> vibratingSensor = sensorList.stream().filter(it -> it.equals("振弦")).collect(Collectors.toList());
        resultInterval.append(vibratingCollectInstruction(vibratingSensor));

        //处理485数字类传感器
        List<SensorTenantResourceRespVO> digitalSensor = sensorList.stream().filter(it -> it.equals("485数字类传感器")).collect(Collectors.toList());
        resultInterval.append(digitalCollectInstruction(digitalSensor));
        //进行数据回写
        channelWrite(resultHead, resultInterval.toString(), ctx);
    }

    /**
     * 节点上传采集数据
     *
     * @param message
     * @param ctx
     */
    private void platformReceiveCollectData(String message, ChannelHandlerContext ctx) {
        executor.submit(() -> {
            try {
                extractedSensorData(message, ctx);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });


        //返回结果
        StringBuffer resultHead = new StringBuffer();
        resultHead.append(INSTRUCTION_BEGINNING);
        resultHead.append(PLATFORM_RECEIVE_COLLECT_DATA_REPLY);
        resultHead.append(MID);
        //进行数据回写
        channelWrite(resultHead, "", ctx);

    }

    private void extractedSensorData(String message, ChannelHandlerContext ctx) {
        //获取连接通道唯一标识
        ChannelId channelId = ctx.channel().id();
        //解析数据
        //id
        String idHex = message.substring(16, 20);
        String id = BinHexOctUtil.hexStringToString(idHex);
        //数据区长度
        String dataLengthHex = message.substring(20, 24);
        Integer dataLength = Integer.parseInt(dataLengthHex, 16);

        //数据区总长度
        String dataTotalLengthHex = message.substring(24, 28);
        Integer dataTotalLength = Integer.parseInt(dataTotalLengthHex, 16);

        //采集方式 01=交互； 02=自动
        String acquisitionMethods = message.substring(28, 30);

        //时间节点
        Integer dataYear = Integer.parseInt(message.substring(30, 34), 16);
        Integer dataMonth = Integer.parseInt(message.substring(34, 36), 16);
        Integer dataDayOfMonth = Integer.parseInt(message.substring(36, 38), 16);
        Integer dataHour = Integer.parseInt(message.substring(38, 40), 16);
        Integer dataMinute = Integer.parseInt(message.substring(40, 42), 16);
        Integer dataSecond = Integer.parseInt(message.substring(42, 44), 16);

        //指令数
        Integer instructionQuantity = Integer.parseInt(message.substring(44, 46), 16);
        //数据个数
        Integer dataQuantity = Integer.parseInt(message.substring(52, 54), 16);

        //传感器数据
        String totalData = message.substring(54, message.length() - 6);


        List<SensorTenantResourceRespVO> sensorList = CHANNEL_SENSOR.get(channelId);
        McuTenantResourceDO mcu=  CHANNEL_MCU.get(channelId);
        if (CollectionUtil.isEmpty(sensorList)) {
            sensorList = new ArrayList<>();
        }
        //数据解析
        for (int i = 0; i < dataQuantity; i++) {
            //01 为传感器类型，01代表数字类传感器
            String type = totalData.substring(0, 2);
            //单个传感器的业务数据长度
            Integer singleSensorBusinessDataLength = Integer.parseInt(totalData.substring(2, 4), 16);
            //05 代表节点的4通道
            Integer mcuChannel = Integer.parseInt(totalData.substring(4, 6), 16);
            //00 05 为模块号，代表传感器模块号 换算为10进制的 5
            String moduleNo = String.valueOf(Integer.parseInt(totalData.substring(6, 10), 16));
            //01 为子通道号
            String subChannel = totalData.substring(10, 12);
            //单个传感器的业务数据
            String singleSensorBusinessData = totalData.substring(12, (12 + singleSensorBusinessDataLength * 2));

            if (type.equals(VIBRATING_SENSOR_TYPE))
                vibratingDataParse(type, mcuChannel, moduleNo, subChannel, singleSensorBusinessData, sensorList,mcu);
            else if (type.equals(DIGITAL_SENSOR_TYPE))
                digitalDataParse(type, mcuChannel, moduleNo, subChannel, singleSensorBusinessData, sensorList,mcu);

            totalData = totalData.substring(12 + singleSensorBusinessDataLength * 2);

        }
    }

    //振弦数据解析
    private void vibratingDataParse(String type, Integer mcuChannel, String moduleNo, String subChannel, String singleSensorBusinessData, List<SensorTenantResourceRespVO> sensorList,McuTenantResourceDO mcu) {
        Optional<SensorTenantResourceRespVO> sensorOptional = sensorList.stream().filter(it -> it.getMcuChannel().equals(mcuChannel))
                .filter(it ->
                        it.getAttributeMetadata().stream().filter(attribute -> attribute.getCode().equals("type") && attribute.getInputValue().equals("振弦")).findFirst().isPresent()
                )
                .findFirst();
        Boolean sensorExist = sensorOptional.isPresent();
        if (!sensorExist) {
            log.info("没有关联对应的传感器！此数据不进行解析");
            return;
        }
        if (!StringUtils.hasLength(singleSensorBusinessData)) {
            log.info("此业务数据为空！此数据不进行解析");
            return;
        }
        SensorTenantResourceRespVO sensor = sensorOptional.get();
        //振弦采集指令，数据返回是作为记录返回
        String instruction = singleSensorBusinessData.substring(0, 10);
        //00 采集状态
        String acquisitionState = singleSensorBusinessData.substring(10, 12);
        //频率数据
        Double frequencyData = new BigDecimal(Float.intBitsToFloat(Integer.parseUnsignedInt(singleSensorBusinessData.substring(12, 20), 16))).setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
        //幅值数据
        Double amplitudeData = new BigDecimal(Float.intBitsToFloat(Integer.parseUnsignedInt(singleSensorBusinessData.substring(20, 28), 16))).setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
        //温度数据
        Double temperatureData = new BigDecimal(Float.intBitsToFloat(Integer.parseUnsignedInt(singleSensorBusinessData.substring(28, 36), 16))).setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
        //温度编码
        String temperatureCode = singleSensorBusinessData.substring(36, 44);

        MonitoringDataCreateReqVO cmd = new MonitoringDataCreateReqVO();
        cmd.setSensorTenantResourceId(sensor.getId());
        cmd.setMcuTenantResourceId(sensor.getMcuTenantResourceId());
        cmd.setMcuModel(sensor.getMcuModel());
        cmd.setSensorName(sensor.getName());
        cmd.setSensorModel(sensor.getModel());
        cmd.setTenantId(sensor.getTenantId());
        cmd.setValueMetadata(
                sensor.getValueMetadata().stream().map(it -> {
                    CustomValueFields valueFields = new CustomValueFields();
                    valueFields.setCode(it.getCode());
                    valueFields.setName(it.getName());
                    valueFields.setIsShow(it.getIsShow());
                    valueFields.setSorts(it.getSorts());
                    if (it.getCode().equals("frequency"))
                        valueFields.setValue(frequencyData);
                    else if (it.getCode().equals("amplitude"))
                        valueFields.setValue(amplitudeData);
                    else if (it.getCode().equals("temperature"))
                        valueFields.setValue(temperatureData);
                    else valueFields.setValue(0.0);

                    return valueFields;
                }).collect(Collectors.toList()));

        List<MonitoringWarningLogCreateReqVO> monitoringWarningLogs = warningContrast(sensor, cmd,mcu);
        if (!monitoringWarningLogs.isEmpty())
            monitoringWarningLogService.createBatchMonitoringWarningLog(monitoringWarningLogs);
        monitoringDataService.createMonitoringData(cmd);
    }

    //485数据解析
    private void digitalDataParse(String type, Integer mcuChannel, String moduleNo, String subChannel, String singleSensorBusinessData, List<SensorTenantResourceRespVO> sensorList,McuTenantResourceDO mcu) {
        Optional<SensorTenantResourceRespVO> sensorOptional = sensorList.stream().filter(it -> it.getMcuChannel().equals(mcuChannel))
                .filter(it ->
                        it.getAttributeMetadata().stream().filter(attribute -> attribute.getCode().equals("type") && attribute.getInputValue().equals("485数字类传感器")).findFirst().isPresent()
                )
                .findFirst();
        Boolean sensorExist = sensorOptional.isPresent();
        if (!sensorExist) {
            log.info("没有关联对应的传感器！此数据不进行解析");
            return;
        }
        if (!StringUtils.hasLength(singleSensorBusinessData)) {
            log.info("此业务数据为空！此数据不进行解析");
            return;
        }
        SensorTenantResourceRespVO sensor = sensorOptional.get();
        //协议号
        Integer agreementNo = Integer.parseInt(singleSensorBusinessData.substring(0, 4), 16);
        //模块号
        Integer moduleNo1 = Integer.parseInt(singleSensorBusinessData.substring(4, 8), 16);
        //01 为子通道
        String subChannel1 = singleSensorBusinessData.substring(8, 10);
        //数据个数
        Integer dataQuantity = Integer.parseInt(singleSensorBusinessData.substring(10, 12), 16);

        MonitoringDataCreateReqVO cmd = new MonitoringDataCreateReqVO();
        List<CustomValueFields> valueMetadata = new ArrayList<>();
        cmd.setSensorTenantResourceId(sensor.getId());
        cmd.setMcuTenantResourceId(sensor.getMcuTenantResourceId());
        cmd.setMcuModel(sensor.getMcuModel());
        cmd.setSensorName(sensor.getName());
        cmd.setSensorModel(sensor.getModel());
        cmd.setValueMetadata(valueMetadata);
        cmd.setTenantId(sensor.getTenantId());
        for (int i = 0; i < dataQuantity; i++) {
            Double data = new BigDecimal(Float.intBitsToFloat(Integer.parseUnsignedInt(singleSensorBusinessData.substring(12 + (i * 8), 20 + (i * 8)), 16))).setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
            CustomValueFields valueFields = new CustomValueFields();
            valueFields.setCode(sensor.getValueMetadata().get(i).getCode());
            valueFields.setName(sensor.getValueMetadata().get(i).getName());
            valueFields.setIsShow(sensor.getValueMetadata().get(i).getIsShow());
            valueFields.setSorts(sensor.getValueMetadata().get(i).getSorts());
            valueFields.setValue(data);
            valueMetadata.add(valueFields);
        }
        List<MonitoringWarningLogCreateReqVO> monitoringWarningLogs = warningContrast(sensor, cmd,mcu);
        if (!monitoringWarningLogs.isEmpty())
            monitoringWarningLogService.createBatchMonitoringWarningLog(monitoringWarningLogs);
        monitoringDataService.createMonitoringData(cmd);

    }


    /**
     * 预警对比
     * Warning
     */
    private List<MonitoringWarningLogCreateReqVO> warningContrast(SensorTenantResourceRespVO sensor, MonitoringDataCreateReqVO data,McuTenantResourceDO mcu) {
        List<MonitoringWarningLogCreateReqVO> list = new ArrayList<>();
        for (CustomValueFields valueFields : data.getValueMetadata()) {
            for (CustomWarningAttribute warningAttribute : sensor.getWarningMetadata()) {
                if (StringUtils.hasLength(warningAttribute.getConditions()) &&
                        valueFields.getCode().equals(warningAttribute.getCode()) &&
                        ((warningAttribute.getConditions().equals("大于") && valueFields.getValue() > warningAttribute.getValue()) ||
                                (warningAttribute.getConditions().equals("小于") && valueFields.getValue() < warningAttribute.getValue()) ||
                                (warningAttribute.getConditions().equals("等于") && valueFields.getValue() == warningAttribute.getValue()))
                ) {
                    MonitoringWarningLogCreateReqVO warningLog = new MonitoringWarningLogCreateReqVO();
                    warningLog.setSensorTenantResourceId(data.getSensorTenantResourceId());
                    warningLog.setMcuTenantResourceId(data.getMcuTenantResourceId());
                    warningLog.setTenantId(data.getTenantId());
                    warningLog.setMonitoringValue(String.valueOf(valueFields.getValue()));
                    warningLog.setWarningMetadata(warningAttribute);
                    list.add(warningLog);
                }
            }
        }

        if (!list.isEmpty()) {
            list.stream().map(it -> {
                //您的设备:备注1,8通道号传感器的预警'温度'大于32,触发了预警，值为 56
                //您的设备:#name#,#mcuChannel#通道号传感器的预警#code#、#conditions#、#value#,触发了预警，值为#monitoringValue#
                StringBuilder output = new StringBuilder();
                output.append("您的MCU[编号：").append(mcu.getModel()).append(" 名称为：").append(mcu.getName()).append("  备注：").append(mcu.getRemark()).append("  经纬度：")
                        .append(mcu.getLongitude()).append(",").append(mcu.getLatitude()).append("] 上绑定的传感器[编号：").append(sensor.getModel()).append(" 名称为：").append(sensor.getName())
                        .append("  备注：").append(sensor.getRemark()).append("   绑定通道号：").append(sensor.getMcuChannel()).append("] 设置的预警 '").append(it.getWarningMetadata().getName())
                        .append("' ").append(it.getWarningMetadata().getConditions()).append(" ").append(it.getWarningMetadata().getValue()).append("  触发了预警，数据值为 ").append(it.getMonitoringValue());
               it.setLogTemplate(output.toString());
                return it;
            }).collect(Collectors.toList());

        }
        return list;
    }


    //振弦采集指令组装
    private StringBuffer vibratingCollectInstruction(List<SensorTenantResourceRespVO> vibratingSensor) {
        StringBuffer sb = new StringBuffer();
        vibratingSensor.forEach(it -> {
            //01    00 00 00 00     01    00   18    05 01 19 23 05 00 05 E1 00 01
            //01 代表1通道
            sb.append(BinHexOctUtil.intToHexString(it.getMcuChannel(), 2));
            //00 00 00 00  代表传感器ID
            sb.append(BinHexOctUtil.intToHexString(it.getId().intValue(), 8));
            //01 代表子指令个数
            sb.append(CHILD_INSTRUCTION_QUANTITY1);
            //00  传感器类型 0=振弦，1=485数字类传感器
            sb.append(VIBRATING_SENSOR_TYPE);

            //18 选项1 ，振弦时为振弦采集配置
            /**
             B0：放大器增益倍数:0=100倍，1=500倍（默认为0）
             B1：是否发激励信号：0=是，1=否(默认为0)
             B2：是否检测线状态：0=是，1=否(默认为0)
             B3：是否上传振弦频谱:0 =是，1 =否(默认为1)
             B4-B5：采样频率：0=8K，1 =16K，2=32K(默认为1)
             B6-B7：激励方式：0=单脉冲激励，1=多脉冲激励，2=共振激励(默认为0)
             */

            //获取振弦配置
            String incentiveType = "";
            String frequency = "";
            String spectrum = "";
            String detection = "";
            String incentive = "";
            String amplifier = "";
            String beforeDelay = "25";
            String afterDelay = "25";
            String initialFrequency = null;
            for (CustomSensorAttribute attribute : it.getAttributeMetadata()) {
                if (attribute.getCode().equals("incentiveType")) {
                    incentiveType = attribute.getInputValue();
                } else if (attribute.getCode().equals("frequency")) {
                    frequency = attribute.getInputValue();
                } else if (attribute.getCode().equals("spectrum")) {
                    spectrum = attribute.getInputValue();
                } else if (attribute.getCode().equals("detection")) {
                    detection = attribute.getInputValue();
                } else if (attribute.getCode().equals("incentive")) {
                    incentive = attribute.getInputValue();
                } else if (attribute.getCode().equals("amplifier")) {
                    amplifier = attribute.getInputValue();
                } else if (attribute.getCode().equals("beforeDelay")) {
                    beforeDelay = attribute.getInputValue();
                } else if (attribute.getCode().equals("afterDelay")) {
                    afterDelay = attribute.getInputValue();
                } else if (attribute.getCode().equals("initialFrequency")) {
                    initialFrequency = attribute.getInputValue();
                }
            }

            StringBuffer configurationSB = new StringBuffer();
            //激励方式
            if (incentiveType.equals("多脉冲激励"))
                configurationSB.append("01");
            else if (incentiveType.equals("多脉冲激励"))
                configurationSB.append("10");
            else configurationSB.append("00");

            //采样频率
            if (frequency.equals("8K"))
                configurationSB.append("00");
            else if (frequency.equals("32K"))
                configurationSB.append("10");
            else configurationSB.append("01");

            //是否上传振弦频谱
            if (StringUtils.hasLength(spectrum) && spectrum.equals("false"))
                configurationSB.append("1");
            else configurationSB.append("0");

            //是否检测线状态
            if (StringUtils.hasLength(detection) && detection.equals("false"))
                configurationSB.append("1");
            else configurationSB.append("0");

            //是否发激励信号
            if (StringUtils.hasLength(incentive) && incentive.equals("false"))
                configurationSB.append("1");
            else configurationSB.append("0");

            //放大器增益倍数
            if (amplifier.equals("500倍"))
                configurationSB.append("1");
            else configurationSB.append("0");

            //转成一位的hex字符配置（二进制字符串转10转16）
            sb.append(BinHexOctUtil.intToHexString(Integer.valueOf(configurationSB.toString(), 2), 2));
            //数据填充
            sb.append("0001");

            //前延时
            sb.append(BinHexOctUtil.intToHexString(Integer.parseInt(beforeDelay), 2));
            //后延时
            sb.append(BinHexOctUtil.intToHexString(Integer.parseInt(afterDelay), 2));

            //指令长度 05
            sb.append(INSTRUCTION_LENGTH);
            //数据填充
            sb.append(DATA_FILLING1);

            //05 E1 振弦初始频率 换算得1505
            sb.append(BinHexOctUtil.intToHexString(Integer.parseInt(initialFrequency), 4));

            //数据填充 2个hex字节
            sb.append("0001");
        });

        return sb;
    }

    //485数字类采集指令组装
    private StringBuffer digitalCollectInstruction(List<SensorTenantResourceRespVO> digitalSensor) {
        StringBuffer sb = new StringBuffer();
        digitalSensor.forEach(it -> {
            //02  00 00 00 00    01   01   05   05   01   19 23 05 23 2D 00 01 01
            //02 代表2通道
            sb.append(BinHexOctUtil.intToHexString(it.getMcuChannel(), 2));
            //00 00 00 00  代表传感器ID
            sb.append(BinHexOctUtil.intToHexString(it.getId().intValue(), 8));
            //01 代表子指令个数
            sb.append(CHILD_INSTRUCTION_QUANTITY1);
            //01  传感器类型 0=振弦，1=485数字类传感器
            sb.append(DIGITAL_SENSOR_TYPE);

            //05 选项1 ，485配置
            /** 00 00 01 01
             B0-B1：波特率：0=2400，1=9600，2=19200， 3=115200
             B2-B3：数据位：0= 7位，1=8位，2=9位(STM32只支持8位和9位)
             B4-B5：校验位：0=无校验，1=奇校验，2=偶校验
             B6-B7：停止位：0=1位，1=1.5位，2=2位
             */
            //获取振弦配置
            String stopBit = "";
            String checkBit = "";
            String dataBits = "";
            String baudRate = "";
            String beforeDelay = "25";
            String afterDelay = "25";
            String agreementNo = "1503";
            String moduleNo = "1";
            for (CustomSensorAttribute attribute : it.getAttributeMetadata()) {
                if (attribute.getCode().equals("stopBit")) {
                    stopBit = attribute.getInputValue();
                } else if (attribute.getCode().equals("checkBit")) {
                    checkBit = attribute.getInputValue();
                } else if (attribute.getCode().equals("dataBits")) {
                    dataBits = attribute.getInputValue();
                } else if (attribute.getCode().equals("baudRate")) {
                    baudRate = attribute.getInputValue();
                } else if (attribute.getCode().equals("beforeDelay")) {
                    beforeDelay = attribute.getInputValue();
                } else if (attribute.getCode().equals("afterDelay")) {
                    afterDelay = attribute.getInputValue();
                } else if (attribute.getCode().equals("agreementNo")) {
                    agreementNo = attribute.getInputValue();
                } else if (attribute.getCode().equals("moduleNo")) {
                    moduleNo = attribute.getInputValue();
                }
            }
            StringBuffer configurationSB = new StringBuffer();
            //停止位
            if (stopBit.equals("1.5位"))
                configurationSB.append("01");
            else if (stopBit.equals("2位"))
                configurationSB.append("10");
            else configurationSB.append("00");

            //校验位
            if (checkBit.equals("奇校验"))
                configurationSB.append("01");
            else if (checkBit.equals("偶校验"))
                configurationSB.append("10");
            else configurationSB.append("00");

            //数据位
            if (dataBits.equals("7位"))
                configurationSB.append("00");
            else if (dataBits.equals("9位"))
                configurationSB.append("10");
            else configurationSB.append("01");

            //波特率
            if (baudRate.equals("2400"))
                configurationSB.append("00");
            else if (baudRate.equals("19200"))
                configurationSB.append("10");
            else if (baudRate.equals("115200"))
                configurationSB.append("11");
            else configurationSB.append("01");

            //转成一位的hex字符配置（二进制字符串转10转16）
            sb.append(BinHexOctUtil.intToHexString(Integer.valueOf(configurationSB.toString(), 2), 2));

            //485切换时间：备用，默认为0；
            sb.append(DATA_FILLING1);
            //编解码配置：1 = 设备编解码，2 = 软件编解码，设备透传，默认为1；
            sb.append("01");

            //前延时
            sb.append(BinHexOctUtil.intToHexString(Integer.parseInt(beforeDelay), 2));

            //后延时
            sb.append(BinHexOctUtil.intToHexString(Integer.parseInt(afterDelay), 2));

            //指令长度 05
            sb.append(INSTRUCTION_LENGTH);

            //23 2D 协议号  9005
            sb.append(BinHexOctUtil.intToHexString(Integer.valueOf(agreementNo), 4));
            //00 01 模块号 01
            sb.append(BinHexOctUtil.intToHexString(Integer.valueOf(moduleNo), 4));

            //数据填充 指令结尾
            sb.append(WHETHER_DATA_TAIL_PACKET1);
        });

        return sb;
    }


    /**
     * 数据校验
     */
    private boolean validationData(String message) {
        //进行数据校验
        String crc16Code = message.substring(message.length() - 6, message.length() - 2);
        if (BinHexOctUtil.makeCRC(message.substring(0, message.length() - 6), false).equals(crc16Code))
            return true;
        return false;
    }


    /**
     * 注册包
     *
     * @param message
     * @param ctx
     */
    private void registrationPacket(String message, ChannelHandlerContext ctx) {
        //获取连接通道唯一标识
        ChannelId channelId = ctx.channel().id();
        String id = BinHexOctUtil.hexStringToString(message.substring(0, 8));
        String phone = BinHexOctUtil.hexToAscii(message.substring(8, 30));
        String ip = BinHexOctUtil.hexStringToString(message.substring(32, 40));

        //TODO  测试数据
       // phone = "13127556881";

        //根据手机号获取关联的 Mcu
        List<McuTenantResourceDO> mcuList = mcuTenantResourceService.getMcuTenantResourceList(McuTenantResourceListReqVO.builder().correlationIp(phone).build());
        if (CollectionUtil.isEmpty(mcuList)) {
            log.error("手机号为：{1},不存在绑定的设备，不进行数据处理", phone);
            return;
        }
        if (mcuList.size() > 1) {
            log.error("手机号为：{1},存在多个绑定的设备，不进行数据处理", phone);
            return;
        }

        McuTenantResourceDO mcu = mcuList.get(0);
        List<SensorTenantResourceDO> sensorList = sensorTenantResourceService.getSensorTenantResourceList(SensorTenantResourceListReqVO.builder().mcuTenantResourceId(mcu.getId()).build());
        if (CollectionUtil.isEmpty(sensorList)) {
            log.error("手机号为：{1},绑定的设备，没有关联的传感器！不进行数据处理", phone);
            return;
        }
        CHANNEL_SENSOR.put(channelId, SensorTenantResourceConvert.convertList(sensorList));
        //获取对应的MCU设备
        CHANNEL_MCU.put(channelId, mcu);
      
    }


    /**
     * @param resultHead     数据头部 （包含 1.指令固定开头,2. 指令清单 3.消息id）
     * @param resultInterval 数据区 (用于计算数据区长度)
     * @param ctx            连接通道唯一id
     * @author xiongchuan on 2019/4/28 16:10
     * @DESCRIPTION: 服务端给客户端发送消息
     * @return:
     */
    public void channelWrite(StringBuffer resultHead, String resultInterval, ChannelHandlerContext ctx) {
        //计算数据区的长度
        String dataLength = BinHexOctUtil.intToHexString((resultInterval.length() / 2), 4);
        resultHead.append(dataLength);
        resultHead.append(resultInterval);
        //计算CRC16 校验码
        resultHead.append(BinHexOctUtil.makeCRC(resultHead.toString(), false));
        //拼接结尾
        resultHead.append(INSTRUCTION_END);
        //将客户端的信息直接返回写入ctx

        System.out.println("回复数据："+resultHead.toString());
        ctx.writeAndFlush(resultHead.toString());
    }

    /**
     * 有客户端终止连接服务器会触发此函数
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        ChannelId channelId = ctx.channel().id();
        //包含此客户端才去删除
        if (CHANNEL_MCU.containsKey(channelId)) {
            CHANNEL_MCU.remove(channelId);
            CHANNEL_SENSOR.remove(channelId);
            log.info("客户端【" + channelId + "】退出netty服务器[IP:" + clientIp + "--->PORT:" + insocket.getPort() + "]");
            log.info("连接通道数量: " + CHANNEL_MCU.size());
        }
    }

    /**
     * 异常捕获
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
        log.info(ctx.channel().id() + " 发生了错误,此连接被关闭" + "此时连通数量: " + CHANNEL_MCU.size());
        cause.printStackTrace();
    }
}

